package cn.tedu.mall.front.service.impl;

import cn.tedu.mall.common.exception.CoolSharkServiceException;
import cn.tedu.mall.common.restful.ResponseCode;
import cn.tedu.mall.front.mappers.FrontSkuMapper;
import cn.tedu.mall.front.service.IFrontSkuService;
import cn.tedu.mall.pojo.front.entity.FrontStockLog;
import cn.tedu.mall.pojo.order.dto.OrderItemAddDTO;
import cn.tedu.mall.pojo.product.vo.SkuStandardVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
@DubboService
public class FrontSkuServiceImpl extends FrontCacheServiceImpl<SkuStandardVO> implements IFrontSkuService {

    private static final String FRONT_SKU_PREFIX = "front:sku:";
    private static final String FRONT_SKUS_PREFIX = "front:skus:";
    private static final String FRONT_SKUS_LOCK_SUFFIX = ".lock";

    private final FrontSkuMapper frontSkuMapper;

    @Autowired
    public FrontSkuServiceImpl(FrontSkuMapper frontSkuMapper) {
        this.frontSkuMapper = frontSkuMapper;
    }

    @Override
    public List<SkuStandardVO> getSkus(Long spuId) {
        String skusKey = FRONT_SKUS_PREFIX + spuId;
        List<SkuStandardVO> fromRedis = getListFromRedis(skusKey);
        if (CollectionUtils.isEmpty(fromRedis)) {
            String skusLockKey = skusKey + FRONT_SKUS_LOCK_SUFFIX;
            String skusLockRand = new Random().nextInt(9000) + 1000 + "";
            try {
                if (!tryLock(skusLockKey, skusLockRand)) {
                    log.info("获取锁失败！");
                    Thread.sleep(5000);
                    return getListFromRedis(skusKey);
                }
                log.info("获取锁成功！执行查询数据库逻辑");
                List<SkuStandardVO> skuList = frontSkuMapper.getSkuList(spuId);
                if (CollectionUtils.isEmpty(skuList)) {
                    throw new CoolSharkServiceException(ResponseCode.NOT_FOUND, "此id下没有对应的Sku！");
                }
                setListToRedis(skusKey, skuList, 24L * 60 * 60 + (new Random().nextInt(5 * 60 * 60) + 1), TimeUnit.SECONDS);
                return skuList;
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                releaseLock(skusLockKey, skusLockRand);
            }
        }
        return fromRedis;
    }

    @Override
    public SkuStandardVO getSku(Long id) {
        String skuKey = FRONT_SKU_PREFIX + id;
        SkuStandardVO cache = getFromRedis(skuKey);
        if (cache != null) {
            return cache;
        } else {
            cache = frontSkuMapper.getSkuById(id);
            if (cache == null) {
                throw new CoolSharkServiceException(ResponseCode.NOT_FOUND, "没有对应的sku");
            }
            setToRedis(skuKey, cache, 24L * 60 * 60 + (new Random().nextInt(5 * 60 * 60) + 1), TimeUnit.SECONDS);
        }
        return cache;
    }

    @Override
    public List<SkuStandardVO> listSkuByIds(List<Long> ids) {
        List<SkuStandardVO> list = new ArrayList<>();
        for (Long id : ids) {
            String skuKey = FRONT_SKU_PREFIX + id;
            SkuStandardVO cache = getFromRedis(skuKey);
            if (cache != null) {
                list.add(cache);
            } else {
                cache = frontSkuMapper.getSkuById(id);
                if (cache != null) {
                    list.add(cache);
                    setToRedis(skuKey, cache, 24L * 60 * 60 + (new Random().nextInt(5 * 60 * 60) + 1), TimeUnit.SECONDS);
                }
            }
        }
        return list;
    }

    @Override
    @Transactional
    public void reduceSkusCounts(List<OrderItemAddDTO> items, String sn) {
        for (OrderItemAddDTO item : items) {
            Long skuId = item.getSkuId();
            Integer quantity = item.getQuantity();
            int i = frontSkuMapper.decrStock(skuId, quantity);
            if (i == 0) {
                throw new CoolSharkServiceException(ResponseCode.BAD_REQUEST, "当前库存扣减失败，库存数量不够，skuId：" + skuId);
            }
            // 成功减一个库存，就记录一条日志
            FrontStockLog frontStockLog = new FrontStockLog();
            frontStockLog.setSkuId(skuId);
            frontStockLog.setOrderSn(sn);
            frontStockLog.setQuantity(quantity);
            frontStockLog.setGmtCreate(LocalDateTime.now());
            frontStockLog.setGmtModified(frontStockLog.getGmtCreate());
            frontSkuMapper.insertStockLog(frontStockLog);
        }
    }

    @Override
    public void returnStock(String sn) {
        // 用订单的sn从日志中查询减库存日志，
        List<FrontStockLog> frontStockLogs = frontSkuMapper.selectStockLogBySn(sn);
        if (frontStockLogs == null || frontStockLogs.size() == 0) {
            // 没有日志记录，说明库存没减
            log.info("sn:{}，没有对应的库存减少日志，不用进行任何操作", sn);
        } else {
            for (FrontStockLog frontStockLog : frontStockLogs) {
                // 还库存
                frontSkuMapper.incrStock(frontStockLog.getSkuId(), frontStockLog.getQuantity());
            }
        }
    }
}
